package kgame5.kgu.move.cd.gridcd {
import kgame5.kgu.move.MapManager;
import kgame5.k3d.core.math.Vector3D;
import kgame5.k3d.core.obj3d.hardvo.HardVO;
import kgame5.kgu.move.cd.BoxBound2D;
import kgame5.kutil.Util;

/*
 * 网格碰撞。这个挺有用的，需要研发出这个东西来
 */
public class GridCollition {
	private var CC:int,RC:int;
	private var CellSize:int;
	
	//网格，是个一维数组，效率吧
	private var grids:Array=null;//GridCell
	
	private var a2Data:Array=null;//int[][] 做寻径用的
	
	// 这个存储了碰撞的物体列表，作为一个整体的四个边界
	public var resultBound :BoxBound2D =new BoxBound2D();
	//地图边界
	private var mapBound:BoxBound2D =new BoxBound2D();
	
	//hardList是各个物体
	public function Init(CC:int, RC:int, CellSize:int, hardList:Array):void{
		//
		this.CC=CC;
		this.RC=RC;
		this.CellSize=CellSize;
		grids=new Array();//GridCell[CC*RC];
		
		//
		a2Data=Util.NewArray2_Int(RC, CC);
		
		//-地图边框
		mapBound.left=0;
		mapBound.right=CC*CellSize;
		mapBound.up=0;
		mapBound.down=-RC*CellSize;
		
		//添加
		if(hardList!=null){
			for each(var hard:HardVO in hardList){
				Add(hard);
			}
		}
	}
	
	//给一个hardVO填充col和row
	public function fillColAndRow(hard:HardVO):void{
		hard._col=MapManager.calcCol(hard.v3d_p.x,CellSize);
		hard._row=MapManager.calcRow(hard.v3d_p.z,CellSize);
	}
	
	//检测此网格是不是有障碍物，出了边界的，认为有障碍物
	public function isBlock(col:int,row:int):Boolean{
		//取得索引
		var idx:int=calcIdx(col,row);
		if(idx==-1){//出边界了
			return true;
		}
		
		return a2Data[row][col]==1;
	}
	
	//测试前方是否有障碍物
	//原理是把位置先尝试加到指定位置，然后看是否有障碍物
	public function isBlockAhead(hardVO:HardVO):Boolean{
		var preX:int=hardVO.v3d_p.x;
		var preY:int=hardVO.v3d_p.y;
		var preZ:int=hardVO.v3d_p.z;
		
		//尝试加到指定位置
		hardVO.v3d_p.add(hardVO.v3d_v);
		
		var isCollide:Boolean=mapBound.contains(hardVO)==false||FastCD(hardVO);
		
		hardVO.v3d_p.x=preX;
		hardVO.v3d_p.y=preY;
		hardVO.v3d_p.z=preZ;
		
		return isCollide;
	}
	
	//是撞上了障碍物和超出了边界
	public function isCollide(hardVO:HardVO):Boolean{
		return mapBound.contains(hardVO)==false||FastCD(hardVO);
	}
	
	//~四个方向中，找到一个可以走的方向,这个是npc用的.此函数实现的不是很好
	public function getOpenDirs4(hard:HardVO ):Array{
		var a:Array=new Array();
		//上下左右
		var col:int=hard._col;
		var row:int=hard._row;
		
		if(isBlock(col, row-1)==false){
			a.add(MapManager.DIR_UP);
		}
		if(isBlock(col, row+1)==false){
			a.add(MapManager.DIR_DOWN);
		}
		if(isBlock(col-1, row)==false){
			a.add(MapManager.DIR_LEFT);
		}
		if(isBlock(col+1, row-1)==false){
			a.add(MapManager.DIR_RIGHT);
		}
		
		return a;
	}
	
//	//测试方向上的前一个格子是否是障碍物
//  //这个是个无效的
//	public function isBlockAhead( hard:HardVO):Boolean{
//		var col:int=PosiM4.calcCol(hard.v3d_p.x, CellSize);
//		var row:int=PosiM4.calcRow(hard.v3d_p.z, CellSize);
//		
//		switch(hard.v3d_r.y){
//			case 0:
//			return isBlock(col, row-1);
//			case 90:
//			return isBlock(col+1, row);
//			case 180:
//			return isBlock(col, row+1);
//			case 270:
//			return isBlock(col-1, row);
//		}
//		
//		return true;
//	}
	//敌人是否在前方，用网格判断
	public function isEnemyAhead(me:HardVO,em:HardVO):Boolean{
		 switch(me.v3d_r.y){
		 case 0:
			 if(me._col==em._col
					 &&me._row>=em._row){
				 return true;
			 }
					
			 break;
		 
		 case 180:
			 if(me._col==em._col
					 &&me._row<=em._row){
				 return true;
			 }
			 break;
		 case 90:
			 if(me._row==em._row
					 &&me._col<=em._col){
				 return true;
			 }
			 break;
		 case 270:
			 if(me._row==em._row
					 &&me._col>=em._col){
				 return true;
			 }
			 break;
		 }
		 return false;
	}
	//添加一个障碍物
	public function Add(hard:HardVO ):void{
		
		//-保证都是2的倍数！！很重要，否则绕行失效
		if(hard.aabb.A%2!=0){
			hard.aabb.A++;
		}
			
		if(hard.aabb.B%2!=0){
			hard.aabb.B++;
		}
		
		//--
		var col:int=MapManager.calcCol(hard.v3d_p.x,CellSize);
		var row:int=MapManager.calcRow(hard.v3d_p.z,CellSize);
		var idx:int=calcIdx(col,row);
			
		//如果需要的时候才创建呢，节约内存
		if(grids[idx]==null){
			var cell:GridCell=new GridCell();
			cell.col=col;
			cell.row=row;
			grids[idx]=cell;
		}
			
		//添加
		grids[idx].listObj.push(hard);
		
		a2Data[row][col]=1;//障碍物标志
	}
	
	//删除一个障碍物
	public function Remove(srcVO:HardVO ):void{
		var col:int=MapManager.calcCol(srcVO.v3d_p.x,CellSize);
		var row:int=MapManager.calcRow(srcVO.v3d_p.z,CellSize);
		var idx:int=calcIdx(col,row);
		var cell:GridCell=grids[idx];
		if(cell!=null){
			/*原版
			for(var i:int=0;i<cell.listObj.length;i++){
				if(cell.listObj[i]==srcVO){
					cell.listObj.splice(i,1);
				}
			}
			//-###曾经这样写，出了错flash里可没有这个remove啊!
			//cell.listObj.remove(srcVO);
			//*/
			
			//删除
			var idx:int=cell.listObj.indexOf(srcVO);
			if(idx!=-1){
				cell.listObj.splice(idx, 1);
			}
			
			//障碍物标志清空
			a2Data[row][col]=0;
		}
	}
	
	//快速检测碰撞。这个的原理是有碰撞则返回true,不需要知道详细的碰撞信息
	public function FastCD(srcVO:HardVO):Boolean{
		var col:int=MapManager.calcCol(srcVO.v3d_p.x,CellSize);
		var row:int=MapManager.calcRow(srcVO.v3d_p.z,CellSize);
		
		return cellCDFast(srcVO,col-1,row-1)
		||cellCDFast(srcVO,col,row-1)
		||cellCDFast(srcVO,col+1,row-1)
		||cellCDFast(srcVO,col-1,row)
		||cellCDFast(srcVO,col,row)
		||cellCDFast(srcVO,col+1,row)
		||cellCDFast(srcVO,col-1,row+1)
		||cellCDFast(srcVO,col,row+1)
		||cellCDFast(srcVO,col+1,row+1);
	}
	
	//返回与srcVO碰撞的所有的HardVO
	public function BestCD(srcVO:HardVO ):Array {
		
		//结果的边界
		clearResultBound();
		
		var col:int=MapManager.calcCol(srcVO.v3d_p.x,CellSize);
		var row:int=MapManager.calcRow(srcVO.v3d_p.z,CellSize);
		var _result:Array = new Array();
		
		cellCDBest(srcVO,col-1,row-1,_result);
		cellCDBest(srcVO,col,row-1,_result);
		cellCDBest(srcVO,col+1,row-1,_result);
		
		cellCDBest(srcVO,col-1,row,_result);
		cellCDBest(srcVO,col,row,_result);//这个是可选的。如果是泡泡堂，则这个暂时不考虑
		cellCDBest(srcVO,col+1,row,_result);
		
		cellCDBest(srcVO,col-1,row+1,_result);
		cellCDBest(srcVO,col,row+1,_result);
		cellCDBest(srcVO,col+1,row+1,_result);
		
		return _result;
	}
	
	//检测一个格子里的碰撞,结果放到_result里
	private function cellCDBest(srcVO:HardVO , col:int, row:int,_result:Array):void{
		
		//取得索引
		var idx:int=calcIdx(col,row);
		if(idx==-1){//出边界了
			return;
		}
		//取得网格
		var cell:GridCell=grids[idx];
		if(cell==null){
			return;
		}
		//检测与网格内的各个物体的碰撞
		for each(var aimVO :HardVO in cell.listObj){
			if(srcVO.HitTestAABB(aimVO)){
				//添加到结果
				_result.push(aimVO);
				
				//更新结果边界
				refreshResultBound(aimVO);
			}
		}
	}
	//检测一个格子里的碰撞,结果放到_result里
	private function cellCDFast(srcVO:HardVO , col:int, row:int):Boolean{
		//取得索引
		var idx:int=calcIdx(col,row);
		if(idx==-1){//出边界了
			return false;
		}
		//取得网格
		var cell:GridCell=grids[idx];
		if(cell==null){
			return false;
		}
		//检测与网格内的各个物体的碰撞
		for each(var aimVO :HardVO in cell.listObj){
			if(srcVO.HitTestAABB(aimVO)){
				return true;
			}
		}
		return false;
	}
	private function calcIdx(col:int, row:int):int{
		if(col<0||col>CC-1||row<0||row>RC-1){
			return -1;
		}
		return row*CC+col;
	}
	
	private function clearResultBound():void{
		resultBound.left=mapBound.right;
		resultBound.right=mapBound.left;
		resultBound.up=mapBound.down;
		resultBound.down=mapBound.up;
	}
	private function refreshResultBound(aimVO:HardVO ):void{
		var A2:int=aimVO.aabb.A/2;
		var B2:int=aimVO.aabb.B/2;
		var p:Vector3D=aimVO.v3d_p;
		var l:int=p.x-A2;
		var r:int=p.x+A2;
		var u:int=p.z+B2;
		var d:int=p.z-B2;
		resultBound.left=Math.min(resultBound.left, l);
		resultBound.right=Math.max(resultBound.right, r);
		
		resultBound.up=Math.max(resultBound.up, u);
		resultBound.down=Math.min(resultBound.down, d);
		
		//中心点，注意这个会有误差的
		resultBound.x=(resultBound.left+resultBound.right)/2;
		resultBound.z=(resultBound.up+resultBound.down)/2;
	}
	
}
}
